package com.feiwo.nonego.rpc.provider.common.server.base;

import com.feiwo.nonego.rpc.codec.RpcDecoder;
import com.feiwo.nonego.rpc.codec.RpcEncoder;
import com.feiwo.nonego.rpc.common.util.NettyUtils;
import com.feiwo.nonego.rpc.common.util.StringUtils;
import com.feiwo.nonego.rpc.provider.common.handler.RpcProviderHandler;
import com.feiwo.nonego.rpc.provider.common.server.RpcServer;
import com.feiwo.nonego.rpc.registry.ZookeeperRegistryService;
import com.feiwo.nonego.rpc.registry.api.RegistryService;
import com.feiwo.nonego.rpc.registry.api.config.RegistryConfig;
import com.feiwo.nonego.rpc.registry.api.enums.RegistryType;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.socket.SocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * @author feiwo 2025-08-04
 */
public class BaseServer implements RpcServer {

    private final Logger LOGGER = LoggerFactory.getLogger(BaseServer.class);

    protected String host = "127.0.0.1";

    protected int port = 21770;

    protected Map<String,Object> handlerMap = new HashMap<>();

    protected String reflectType = "jdk";

    protected RegistryService registryService;

    public BaseServer() {
    }

    public BaseServer(String severAddress, String registryAddress, String reflectType, RegistryType registryType, String loadBalancerType) {
        if (!StringUtils.isEmpty(severAddress)) {
            var addressSplit = severAddress.split(":");
            if (addressSplit.length == 2) {
                this.host = addressSplit[0];
                this.port = Integer.parseInt(addressSplit[1]);
            }
            this.reflectType = reflectType;
            this.registryService = this.getRegistryService(registryAddress, registryType, loadBalancerType);
        }
    }

    private RegistryService getRegistryService(String registryAddress, RegistryType registryType, String loadBalancerType) {
        switch (registryType) {
            case NACOS:
                return null;
            case ZOOKEEPER: {
                registryService = new ZookeeperRegistryService();
                try {
                    registryService.init(new RegistryConfig(registryAddress, registryType, loadBalancerType));
                } catch (Exception e) {
                    return null;
                }
                return registryService;
            }
            default:
                return null;
        }
    }

    /**
     * 启动Netty服务器
     * 该方法负责初始化Netty服务器，配置网络参数，绑定端口并启动服务
     * 主要包括创建事件循环组、配置服务器启动参数、设置管道处理器等操作
     */
    @Override
    public void startNettyServer() {
        // 创建boss事件循环组，用于处理连接请求
        var bossGroup = NettyUtils.createEventLoopGroup(1);
        // 创建worker事件循环组，用于处理IO操作
        var workerGroup = NettyUtils.createEventLoopGroup(4);
        try {
            // 创建服务器启动引导程序
            var bootstrap = new ServerBootstrap();
            // 配置服务器参数：设置事件循环组、通道类型、子通道处理器
            bootstrap.group(bossGroup, workerGroup).channel(NettyUtils.getServerSocketChannelClass())
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 配置通道管道，添加字符串编解码器和RPC处理器
                            socketChannel.pipeline()
                                    .addLast(new RpcDecoder())
                                    .addLast(new RpcEncoder())
                                    .addLast(new RpcProviderHandler(reflectType, handlerMap));
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            // 绑定主机和端口，启动服务器并等待绑定完成
            var channelFuture = bootstrap.bind(this.host,this.port).sync();
            LOGGER.info("RPC Server started on port {}", this.port);
            // 等待服务器通道关闭
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            LOGGER.error("RPC Server start error", e);
        }finally {
            // 优雅关闭worker事件循环组
            workerGroup.shutdownGracefully();
            // 优雅关闭boss事件循环组
            bossGroup.shutdownGracefully();
        }
    }
}
